﻿#ifndef APP_PUSH_BASE_H
#define APP_PUSH_BASE_H

#include <vector>
#include <map>
#include <queue>
#include <thread>

#ifdef _WIN32
#include <WinSock2.h>
#else
#include<netinet/in.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>   
#endif

#include "common.h"
#include "net_def.h"
#include "app_message.hpp"
#include "pack_buffer.h"
#include "thread_pool.hpp"

namespace mv {
class app_push_base;

class callback_sink {
public:
	virtual ~callback_sink() {
	};
	virtual void on_connect_status_changed(app_push_base* inst, connect_status oldStatus, connect_status newStatus) = 0;
	virtual void on_app_message_received(app_push_base* inst, app_message& message) = 0;
};

class app_push_base {
public:
	app_push_base(const std::string& _id, const std::string& _addr, const int32_t& _portReceiver, const int32_t& _portSender, const uint8_t& _priority);
	virtual ~app_push_base();
	void set_callback_sink(callback_sink* _sink);
	void set_op_data(std::vector<void*>& vec);
	std::vector<void*>& get_op_data();
	std::string& get_id();
	uint8_t get_priority();
	bool start();
	connect_status check_connect_status(connect_status, int32_t);
	void stop();
	run_status get_run_status();
	int64_t get_last_heartbeat_time();
	int64_t get_last_received_time();
	int32_t get_heartbeat_interval();
	connect_status get_connect_status();
	void set_connect_status(connect_status value);
	void send_msg(const uint8_t* data, const int32_t& len);
	bool send_one_msg(const uint8_t* data, const int32_t& len);
protected:
	virtual bool has_network_connection() = 0;
	virtual void try_system_sleep() = 0;
	virtual bool create_socket() = 0;
	bool reset();
	bool heartbeat();
	bool send(uint8_t cmdType, const uint8_t* data, int32_t len);
	bool send_with_receive_port(uint8_t cmdType, const uint8_t* data, int32_t len);
	void make_request(uint8_t cmdType, const uint8_t* data, int32_t len, std::vector<uint8_t>& request);
	bool receive_data(std::vector<int32_t>& cmds);
	void ack_server();
	void listen_message();
	bool poll(std::vector<int32_t>& cmds);
	void check_disconnect();

	std::string id_;
	std::string server_addr_;
	int32_t server_port_receiver_;
	int32_t server_port_sender_;
	std::string security_;
	// 优先级,一般0代表主，大于0代表备
	uint8_t priority_;
	char login_step_ = 'N'; // N: 尚未开始， R: 接收端口已登录, S: 发送端口已登录
	int64_t last_rtime_ = 0L; // 第一次握手成功的时间
	run_status run_status_ = run_status::stoped;
	bool need_reset_ = true;
	int64_t last_heartbeat_ = 0L;
	int64_t last_received_ = 0L;
	int64_t last_send_msg_ = 0L;
	int32_t heartbeat_interval_ = LOGIN_RETRY_INTERVAL;
	connect_status connect_status_ = connect_status::disconnected;
	std::vector<uint8_t> cur_msg_;
	std::queue<std::vector<uint8_t>> queue_;
	std::mutex mutex_queue_;
	pack_buffer pack_buffer_;

	std::thread* msg_t_ = nullptr;
	std::vector<void*> opdata_;
	std::mutex mutex_status_;

	SOCKET sock_client_receiver_;
	SOCKET sock_client_sender_;
private:
	thread_pool* thread_pool_ = nullptr;
	callback_sink* sink_ = nullptr;
	callback_sink* check_status_sink_ = nullptr;
};
} // namespace mv

#endif // !APP_PUSH_BASE_H

